From 4aa5fba0b59dd685f64cfee799a14ef76aac6d04 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sat, 2 May 2020 10:30:46 -0400 Subject: [PATCH] button: Derive from GtkWidget We want to remove GtkBin and GtkContainer as they don't provide much useful functionality anymore. This requires us to move get_request_mode and compute_expand down. We have to implement GtkBuildable, in order to keep the element in ui files working for buttons. See #2681 --- gtk/gtkbutton.c | 149 +++++++++++++++++++++++++++--------------------- gtk/gtkbutton.h | 6 +- 2 files changed, 88 insertions(+), 67 deletions(-) diff --git a/gtk/gtkbutton.c b/gtk/gtkbutton.c index b161c18059..7c10d21b16 100644 --- a/gtk/gtkbutton.c +++ b/gtk/gtkbutton.c @@ -56,9 +56,11 @@ #include "gtkbuttonprivate.h" #include "gtkactionhelperprivate.h" +#include "gtkbuildable.h" #include "gtkcheckbutton.h" #include "gtkgestureclick.h" #include "gtkeventcontrollerkey.h" +#include "gtkbinlayout.h" #include "gtkimage.h" #include "gtkintl.h" #include "gtklabel.h" @@ -80,6 +82,8 @@ struct _GtkButtonPrivate { + GtkWidget *child; + GtkActionHelper *action_helper; GtkGesture *gesture; @@ -140,50 +144,57 @@ static void gtk_button_grab_notify (GtkWidget *widget, gboolean was_grabbed); static void gtk_button_do_release (GtkButton *button, gboolean emit_clicked); +static void gtk_button_set_child_type (GtkButton *button, guint child_type); +static void gtk_button_buildable_iface_init (GtkBuildableIface *iface); static void gtk_button_actionable_iface_init (GtkActionableInterface *iface); -static void gtk_button_set_child_type (GtkButton *button, guint child_type); - static GParamSpec *props[LAST_PROP] = { NULL, }; static guint button_signals[LAST_SIGNAL] = { 0 }; -G_DEFINE_TYPE_WITH_CODE (GtkButton, gtk_button, GTK_TYPE_BIN, +G_DEFINE_TYPE_WITH_CODE (GtkButton, gtk_button, GTK_TYPE_WIDGET, G_ADD_PRIVATE (GtkButton) + G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE, gtk_button_buildable_iface_init) G_IMPLEMENT_INTERFACE (GTK_TYPE_ACTIONABLE, gtk_button_actionable_iface_init)) static void -gtk_button_add (GtkContainer *container, GtkWidget *child) +gtk_button_unmap (GtkWidget *widget) { - GtkButton *button = GTK_BUTTON (container); - GtkButtonPrivate *priv = gtk_button_get_instance_private (button); - - if (priv->child_type != WIDGET_CHILD) - gtk_container_remove (container, gtk_bin_get_child (GTK_BIN (button))); + GtkButtonPrivate *priv = gtk_button_get_instance_private (GTK_BUTTON (widget)); - gtk_button_set_child_type (button, WIDGET_CHILD); + priv->in_button = FALSE; - GTK_CONTAINER_CLASS (gtk_button_parent_class)->add (container, child); + GTK_WIDGET_CLASS (gtk_button_parent_class)->unmap (widget); } static void -gtk_button_remove (GtkContainer *container, GtkWidget *child) +gtk_button_compute_expand (GtkWidget *widget, + gboolean *hexpand, + gboolean *vexpand) { - GtkButton *button = GTK_BUTTON (container); - - gtk_button_set_child_type (button, WIDGET_CHILD); + GtkButtonPrivate *priv = gtk_button_get_instance_private (GTK_BUTTON (widget)); - GTK_CONTAINER_CLASS (gtk_button_parent_class)->remove (container, child); + if (priv->child) + { + *hexpand = gtk_widget_compute_expand (priv->child, GTK_ORIENTATION_HORIZONTAL); + *vexpand = gtk_widget_compute_expand (priv->child, GTK_ORIENTATION_VERTICAL); + } + else + { + *hexpand = FALSE; + *vexpand = FALSE; + } } -static void -gtk_button_unmap (GtkWidget *widget) +static GtkSizeRequestMode +gtk_button_get_request_mode (GtkWidget *widget) { GtkButtonPrivate *priv = gtk_button_get_instance_private (GTK_BUTTON (widget)); - priv->in_button = FALSE; - - GTK_WIDGET_CLASS (gtk_button_parent_class)->unmap (widget); + if (priv->child) + return gtk_widget_get_request_mode (priv->child); + else + return GTK_SIZE_REQUEST_CONSTANT_SIZE; } static void @@ -191,11 +202,9 @@ gtk_button_class_init (GtkButtonClass *klass) { GObjectClass *gobject_class; GtkWidgetClass *widget_class; - GtkContainerClass *container_class; gobject_class = G_OBJECT_CLASS (klass); widget_class = (GtkWidgetClass*) klass; - container_class = GTK_CONTAINER_CLASS (klass); gobject_class->dispose = gtk_button_dispose; gobject_class->set_property = gtk_button_set_property; @@ -207,9 +216,8 @@ gtk_button_class_init (GtkButtonClass *klass) widget_class->unmap = gtk_button_unmap; widget_class->grab_focus = gtk_widget_grab_focus_self; widget_class->focus = gtk_widget_focus_self; - - container_class->add = gtk_button_add; - container_class->remove = gtk_button_remove; + widget_class->compute_expand = gtk_button_compute_expand; + widget_class->get_request_mode = gtk_button_get_request_mode; klass->clicked = NULL; klass->activate = gtk_real_button_activate; @@ -288,6 +296,7 @@ gtk_button_class_init (GtkButtonClass *klass) G_TYPE_NONE, 0); widget_class->activate_signal = button_signals[ACTIVATE]; + gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT); gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_BUTTON_ACCESSIBLE); gtk_widget_class_set_css_name (widget_class, I_("button")); } @@ -441,6 +450,7 @@ gtk_button_dispose (GObject *object) GtkButton *button = GTK_BUTTON (object); GtkButtonPrivate *priv = gtk_button_get_instance_private (button); + g_clear_pointer (&priv->child, gtk_widget_unparent); g_clear_object (&priv->action_helper); G_OBJECT_CLASS (gtk_button_parent_class)->dispose (object); @@ -537,7 +547,7 @@ gtk_button_get_property (GObject *object, g_value_set_string (value, gtk_button_get_icon_name (button)); break; case PROP_CHILD: - g_value_set_object (value, gtk_button_get_child (button)); + g_value_set_object (value, priv->child); break; case PROP_ACTION_NAME: g_value_set_string (value, gtk_action_helper_get_action_name (priv->action_helper)); @@ -578,6 +588,28 @@ gtk_button_actionable_iface_init (GtkActionableInterface *iface) iface->set_action_target_value = gtk_button_set_action_target_value; } +static GtkBuildableIface *parent_buildable_iface; + +static void +gtk_button_buildable_add_child (GtkBuildable *buildable, + GtkBuilder *builder, + GObject *child, + const gchar *type) +{ + if (GTK_IS_WIDGET (child)) + gtk_button_set_child (GTK_BUTTON (buildable), GTK_WIDGET (child)); + else + parent_buildable_iface->add_child (buildable, builder, child, type); +} + +static void +gtk_button_buildable_iface_init (GtkBuildableIface *iface) +{ + parent_buildable_iface = g_type_interface_peek_parent (iface); + + iface->add_child = gtk_button_buildable_add_child; +} + /** * gtk_button_new: * @@ -787,13 +819,8 @@ gtk_button_set_label (GtkButton *button, g_return_if_fail (GTK_IS_BUTTON (button)); - child = gtk_bin_get_child (GTK_BIN (button)); - - if (priv->child_type != LABEL_CHILD || child == NULL) + if (priv->child_type != LABEL_CHILD || priv->child == NULL) { - if (child != NULL) - gtk_button_remove (GTK_CONTAINER (button), child); - child = gtk_label_new (NULL); if (priv->use_underline) { @@ -801,15 +828,14 @@ gtk_button_set_label (GtkButton *button, gtk_label_set_mnemonic_widget (GTK_LABEL (child), GTK_WIDGET (button)); } if (GTK_IS_CHECK_BUTTON (button)) - { - gtk_label_set_xalign (GTK_LABEL (child), 0.0); - } - gtk_button_add (GTK_CONTAINER (button), child); + gtk_label_set_xalign (GTK_LABEL (child), 0.0); + + gtk_button_set_child (button, child); gtk_widget_remove_css_class (GTK_WIDGET (button), "image-button"); gtk_widget_add_css_class (GTK_WIDGET (button), "text-button"); } - gtk_label_set_label (GTK_LABEL (child), label); + gtk_label_set_label (GTK_LABEL (priv->child), label); gtk_button_set_child_type (button, LABEL_CHILD); g_object_notify_by_pspec (G_OBJECT (button), props[PROP_LABEL]); } @@ -835,10 +861,7 @@ gtk_button_get_label (GtkButton *button) g_return_val_if_fail (GTK_IS_BUTTON (button), NULL); if (priv->child_type == LABEL_CHILD) - { - GtkWidget *child = gtk_bin_get_child (GTK_BIN (button)); - return gtk_label_get_label (GTK_LABEL (child)); - } + return gtk_label_get_label (GTK_LABEL (priv->child)); return NULL; } @@ -853,7 +876,7 @@ gtk_button_get_label (GtkButton *button) */ void gtk_button_set_use_underline (GtkButton *button, - gboolean use_underline) + gboolean use_underline) { GtkButtonPrivate *priv = gtk_button_get_instance_private (button); @@ -865,11 +888,8 @@ gtk_button_set_use_underline (GtkButton *button, { if (priv->child_type == LABEL_CHILD) { - GtkWidget *child; - child = gtk_bin_get_child (GTK_BIN (button)); - - gtk_label_set_use_underline (GTK_LABEL (child), use_underline); - gtk_label_set_mnemonic_widget (GTK_LABEL (child), GTK_WIDGET (button)); + gtk_label_set_use_underline (GTK_LABEL (priv->child), use_underline); + gtk_label_set_mnemonic_widget (GTK_LABEL (priv->child), GTK_WIDGET (button)); } priv->use_underline = use_underline; @@ -937,23 +957,20 @@ gtk_button_set_icon_name (GtkButton *button, const char *icon_name) { GtkButtonPrivate *priv = gtk_button_get_instance_private (button); - GtkWidget *child; g_return_if_fail (GTK_IS_BUTTON (button)); g_return_if_fail (icon_name != NULL); - child = gtk_bin_get_child (GTK_BIN (button)); - - if (priv->child_type != ICON_CHILD || child == NULL) + if (priv->child_type != ICON_CHILD || priv->child == NULL) { - child = gtk_image_new_from_icon_name (icon_name); + GtkWidget *child = gtk_image_new_from_icon_name (icon_name); gtk_button_set_child (GTK_BUTTON (button), child); gtk_widget_remove_css_class (GTK_WIDGET (button), "text-button"); gtk_widget_add_css_class (GTK_WIDGET (button), "image-button"); } else { - gtk_image_set_from_icon_name (GTK_IMAGE (child), icon_name); + gtk_image_set_from_icon_name (GTK_IMAGE (priv->child), icon_name); } gtk_button_set_child_type (button, ICON_CHILD); @@ -976,11 +993,7 @@ gtk_button_get_icon_name (GtkButton *button) g_return_val_if_fail (GTK_IS_BUTTON (button), NULL); if (priv->child_type == ICON_CHILD) - { - GtkWidget *child = gtk_bin_get_child (GTK_BIN (button)); - - return gtk_image_get_icon_name (GTK_IMAGE (child)); - } + return gtk_image_get_icon_name (GTK_IMAGE (priv->child)); return NULL; } @@ -1004,13 +1017,19 @@ void gtk_button_set_child (GtkButton *button, GtkWidget *child) { + GtkButtonPrivate *priv = gtk_button_get_instance_private (button); + g_return_if_fail (GTK_IS_BUTTON (button)); g_return_if_fail (child == NULL || GTK_IS_WIDGET (child)); - if (gtk_bin_get_child (GTK_BIN (button))) - gtk_button_remove (GTK_CONTAINER (button), - gtk_bin_get_child (GTK_BIN (button))); - gtk_button_add (GTK_CONTAINER (button), child); + g_clear_pointer (&priv->child, gtk_widget_unparent); + + priv->child = child; + + if (priv->child) + gtk_widget_set_parent (priv->child, GTK_WIDGET (button)); + + gtk_button_set_child_type (button, WIDGET_CHILD); g_object_notify (G_OBJECT (button), "child"); } @@ -1025,8 +1044,10 @@ gtk_button_set_child (GtkButton *button, GtkWidget * gtk_button_get_child (GtkButton *button) { + GtkButtonPrivate *priv = gtk_button_get_instance_private (button); + g_return_val_if_fail (GTK_IS_BUTTON (button), NULL); - return gtk_bin_get_child (GTK_BIN (button)); + return priv->child; } diff --git a/gtk/gtkbutton.h b/gtk/gtkbutton.h index 64440efb5f..fd4b54122f 100644 --- a/gtk/gtkbutton.h +++ b/gtk/gtkbutton.h @@ -30,7 +30,7 @@ #error "Only can be included directly." #endif -#include +#include G_BEGIN_DECLS @@ -48,7 +48,7 @@ typedef struct _GtkButtonClass GtkButtonClass; struct _GtkButton { /*< private >*/ - GtkBin parent_instance; + GtkWidget parent_instance; }; /** @@ -61,7 +61,7 @@ struct _GtkButton */ struct _GtkButtonClass { - GtkBinClass parent_class; + GtkWidgetClass parent_class; /*< public >*/ -- 2.30.2